package com.ui.basic.controller;

import java.awt.image.BufferedImage;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.jsecurity.SecurityUtils;
import org.jsecurity.authc.UsernamePasswordToken;
import org.jsecurity.mgt.SecurityManager;
import org.jsecurity.realm.jdbc.JdbcRealm;
import org.jsecurity.session.Session;
import org.jsecurity.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import com.common.basic.base.BaseController;
import com.common.basic.util.Globals;
import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.Producer;
import com.ui.basic.command.CommDataLogin;
import com.ui.basic.ibatis.dao.CommonDAO;
import com.ui.basic.ibatis.dao.system.TblSUserDAO;
import com.ui.basic.ibatis.model.system.TblSUser;
import com.ui.basic.ibatis.model.system.TblSUserExample;
import com.ui.basic.listener.UserStream;

@Controller
public class LoginController extends BaseController {
	private static final transient org.apache.commons.logging.Log LOGGER = org.apache.commons.logging.LogFactory
			.getLog(LoginController.class);

	@Autowired
	private JdbcRealm jdbcRealm;
	@Autowired
	private SecurityManager securityManager;
	@Autowired
	private TblSUserDAO userDAO;
	@Autowired
	private CommonDAO commonDAO;

	private Producer captchaProducer = null;

	@Autowired
	public void setCaptchaProducer(Producer captchaProducer) {
		this.captchaProducer = captchaProducer;
	}

	public void setJdbcRealm(JdbcRealm jdbcRealm) {
		this.jdbcRealm = jdbcRealm;
	}

	public void setSecurityManager(SecurityManager securityManager) {
		this.securityManager = securityManager;
	}

	public void setUserDAO(TblSUserDAO userDAO) {
		this.userDAO = userDAO;
	}

	public void setCommonDAO(CommonDAO commonDAO) {
		this.commonDAO = commonDAO;
	}

	@RequestMapping(value = "/login", method = RequestMethod.GET)
	public ModelMap get(HttpServletRequest request) {
		CommDataLogin commDataLogin = new CommDataLogin();

		return new ModelMap("commDataLogin", commDataLogin);
	}

	@SuppressWarnings("unchecked")
	@RequestMapping(value = "/login", method = RequestMethod.POST)
	public String processForm(
			final HttpServletRequest request,
			@ModelAttribute("commDataLogin") CommDataLogin commDataLogin,
			BindingResult result) {

		jdbcRealm.setAuthenticationQuery(getMessage(request, "DEFAULT_AUTHENTICATION_QUERY"));
		jdbcRealm.setUserRolesQuery(getMessage(request, "DEFAULT_USER_ROLES_QUERY"));
		jdbcRealm.setPermissionsQuery(getMessage(request, "DEFAULT_PERMISSIONS_QUERY"));

		List<String> errMsg = commDataLogin.getErrMsg()!=null?commDataLogin.getErrMsg():new ArrayList<String>();
		
		UsernamePasswordToken token;
		String capcha = (String) securityManager.getSubject().getSession().getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
		
		if (capcha != null && commDataLogin.getKaptchafield() != null) {
			if (!capcha.equals(commDataLogin.getKaptchafield())) {
				//**Remarks for byPass the capcha code validation
//				errMsg.add(getMessage(request, "error.kacapcha"));
//				return "login";
			}
		}

		try {
			token = new UsernamePasswordToken(commDataLogin.getUsername(),
					commonDAO.convertMD5(commDataLogin.getPassword()));
//			 token.setRememberMe(true);
			securityManager.login(token);
			
		} catch (Exception e) {
			LOGGER.error(e);
			LOGGER.debug("Error authenticating....");
			errMsg.add(getMessage(request, "error.usernameOrPassword"));
		}

		// ***login failed
		if (errMsg!=null && errMsg.size()>0)
			return "login";

		// ***get User Object and put in session
		TblSUserExample example = new TblSUserExample();
		example.createCriteria().andUsernameEqualTo(commDataLogin.getUsername());
		TblSUser user = null;
		try {
			user = (TblSUser) userDAO.selectByExample(example).get(0);
			if(user.getLocktimestamp()!=null){
				errMsg.add(getMessage(request, "error.login.lock"));
				return "login";
			}
			
            Map<String, UserStream> userstreams = (Map<String, UserStream>) request.getSession().getServletContext().getAttribute(Globals.USERSTREAMS);
            LOGGER.info("User-stream : " + String.valueOf(userstreams.size()));
            Iterator itr = userstreams.keySet().iterator();
            
            // check ip && issso
            boolean accessIp = false;
            if (user.getIp() == null || user.getIp().length() == 0) {
                accessIp = true;
            } else if (user.getIp().equalsIgnoreCase("*")) {
                accessIp = true;
            } else {
                if (user.getIp().length() > 0 && request.getRemoteAddr() != null && request.getRemoteAddr().equalsIgnoreCase(user.getIp())) {
                    accessIp = true;
                }
            }
            
            if (accessIp) {
                if (user.getIssso() != null && user.getIssso().booleanValue()) {
                    boolean passSSO = true;
                    while (itr.hasNext()) {
                        String key = (String) itr.next();
                        UserStream userstream = (UserStream) userstreams.get(key);
                        if (user.getUsername() != null && user.getUsername().length() > 0) {
                            if (user.getUsername().equalsIgnoreCase(userstream.getUserName())) passSSO = false;
                        }
                    }
                    if (!passSSO) {
        				errMsg.add(getMessage(request, "error.login.issso"));
                    }
                }
            } else {
				errMsg.add(getMessage(request, "error.login.ip"));
            }
            
			user.setLastlogintimestamp(new Date());
			userDAO.updateByPrimaryKey(user);
		} catch (SQLException e) {
			LOGGER.error(e);
			errMsg.add(getMessage(request, "error.SQLException", new Object[] { e.getSQLState(), e.getMessage()}));
			return "login";
		}

		// ***login failed
		if (errMsg!=null && errMsg.size()>0){
			return "login";
		}

		Subject currentUser = securityManager.getSubject();
		Session session = currentUser.getSession(true);

		session.setAttribute(Globals.CURRENT_USER_NAME, commDataLogin.getUsername());
		user.setPassword(commDataLogin.getPassword());
		session.setAttribute(Globals.USER_KEY, user);
		
		UserStream userstream = (UserStream) SecurityUtils.getSubject().getSession().getAttribute(Globals.USERSTREAM);
		if(userstream==null)userstream = new UserStream();
		userstream.updateUser(user);
		setNormalTimeout(request);
		
		return "redirect:home";
	}

	@SuppressWarnings("unchecked")
	@RequestMapping(value = "/logout", method = RequestMethod.GET)
	public String processLogout(
			ModelMap model,
			final HttpServletRequest request) {
		LOGGER.debug(">>>>LoginController.processLogout");
		Subject subject = securityManager.getSubject();
		if (subject != null) {
			subject.logout();
		}
		
        HttpSession session = request.getSession(false);
        if( session != null ) {
            session.invalidate();
    		return "redirect:login";
        } else {
        	model.put("commDataLogin", new CommDataLogin());
        	return "login";
        }
        
	}

	@RequestMapping("/captcha-image")
	public ModelAndView handleRequest(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		LOGGER.debug(">>>>LoginController.handleRequest(/captcha-image)");
		// Set to expire far in the past.
		response.setDateHeader("Expires", 0);
		// Set standard HTTP/1.1 no-cache headers.
		response.setHeader("Cache-Control",
				"no-store, no-cache, must-revalidate");
		// Set IE extended HTTP/1.1 no-cache headers (use addHeader).
		response.addHeader("Cache-Control", "post-check=0, pre-check=0");
		// Set standard HTTP/1.0 no-cache header.
		response.setHeader("Pragma", "no-cache");

		// return a jpeg
		response.setContentType("image/jpeg");

		// create the text for the image
		String capText = captchaProducer.createText();

		// store the text in the session
		request.getSession().setAttribute(Constants.KAPTCHA_SESSION_KEY,
				capText);

		// create the image with the text
		BufferedImage bi = captchaProducer.createImage(capText);

		ServletOutputStream out = response.getOutputStream();

		// write the data out
		ImageIO.write(bi, "jpg", out);
		try {
			out.flush();
		} finally {
			out.close();
		}
		return null;
	}
}
